/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.compiler.model.definition;


import java.util.Collection;
import java.util.List;

import dex.compiler.model.base.ParseNode;
import dex.misc.Conversion;
import dex.misc.Converter;


/**
 * A parsed Dex unit.  This is the "unit of compilation" in Dex.
 */
public class Unit extends Container {
	

	/**
	 * The toplevel definitions contained in this unit.
	 */
	private List<ParseNode> toplevel;


	/**
	 * Constructs a new unit.
	 * 
	 * @param params    the name, place, modifer, attributes and comment for the unit
	 * @param imports   the modules this unit imports
	 * @param macros    the macros this unit invokes
	 * @param toplevel   the toplevel definitions contained in this unit
	 */
	public Unit(DefinitionParams params, List<ParseNode> toplevel) {
		super(params, toplevel);
		if (toplevel == null) {
			throw new IllegalArgumentException("toplevel may not be null");
		}
		this.toplevel = toplevel;
	}


	/**
	 * Returns the names of the units imported by this unit.
	 * 
	 * @return  the imports
	 */
	public Collection<Import> getImports() {
		return Conversion.subclasses(toplevel, Import.class);
	}

	
	/**
	 * Returns the names of the imported units.
	 * 
	 * @return  the list of imported unit names
	 */
	public Collection<String> getImportedUnitNames() {
		return new Conversion<ParseNode,String>(toplevel, new Converter<ParseNode,String>() {
			public String convert(ParseNode node) {
				if (!(node instanceof Import)) {
					return null;
				}
				return ((Import)node).getUnitName();
			}
		});
	}

	/**
	 * Returns the macros invoked by this unit.
	 * 
	 * @return  the macros
	 */
	public Collection<Macro> getMacros() {
		return Conversion.subclasses(toplevel, Macro.class);
	}
	

	/**
	 * Returns the user types defined in the unit.
	 * The returned collection will contain any record or class definitions
	 * found in the unit.
	 * 
	 * @return  the user types defined in the unit
	 */
	public Collection<UserType> getUserTypes() {
		return Conversion.subclasses(toplevel, UserType.class);
	}
	
	
	/**
	 * Returns the toplevel functions and variables defined in the source
	 * file.
	 * 
	 * @return  the toplevel functions and variables
	 */
	public Collection<Member> getMembers() {
		return Conversion.subclasses(toplevel, Member.class);
	}
	

	/**
	 * Returns the toplevel definitions defined in this unit.
	 * 
	 * @return  the toplevel definitions
	 */
	public Collection<Definition> getDefinitions() {
		return Conversion.subclasses(toplevel, Definition.class);
	}
	
	
	/**
	 * Returns the toplevel functions defined in this unit.
	 * 
	 * @return  the toplevel functions
	 */
	public Collection<Function> getFunctions() {
		return Conversion.subclasses(toplevel, Function.class);		
	}

	
	/**
	 * Returns the toplevel variables defined in this unit.
	 * 
	 * @return  the toplevel variables
	 */
	public Collection<TypedName> getVariables() {
		return Conversion.subclasses(toplevel, TypedName.class);				
	}

	@Override
	public String toString() {
		StringBuilder result = new StringBuilder();
		print(result);
		result.append("unit ").append(getName()).append("\n\n");
		for (ParseNode n : toplevel) {
			result.append(n).append("\n");
		}
		return result.toString();
	}


}
